﻿using Emgu.CV;
using Emgu.CV.Structure;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PlayCardCapture
{
    public interface ImageManager
    {
        Image<Bgr, Byte> getImage(int i, int j);
        void moveFore(int i, int j);
        void moveBack(int i, int j);
        void reset(int i, int j);
        int PlayerCount { get; }
        int CardPerPlayer { get; }
    }

    abstract class AbstractSingleManager : ImageManager
    {
        protected int playerCount;
        protected int cardPerPlayer;
        protected int[] indexArray;
        protected int[] sourceArray;
        protected int frameCount;
        public AbstractSingleManager(int playerCount,int cardPerPlayer,int[] indexArray)
        {
            this.playerCount = playerCount;
            this.cardPerPlayer = cardPerPlayer;
            this.indexArray = indexArray;
            this.sourceArray = (int[])indexArray.Clone();
        }
        public int PlayerCount
        {
            get { return playerCount; }
        }
        public int CardPerPlayer
        {
            get { return cardPerPlayer; }
        }
        public void moveFore(int i, int j)
        {
            if (indexArray[i * playerCount + j] > 0)
                indexArray[i * playerCount + j]--;
        }
        public void moveBack(int i, int j)
        {
            if (indexArray[i * playerCount + j] < frameCount - 1)
                indexArray[i * playerCount + j]++;
        }
        public void reset(int i, int j)
        {
            indexArray[i * playerCount + j] = sourceArray[i * playerCount + j];
        }
        public abstract Image<Bgr, Byte> getImage(int i, int j);
    }

    class SingleMemoryManager : AbstractSingleManager
    {
        private List<Image<Bgr, Byte>> imageList;

        public SingleMemoryManager(List<Image<Bgr, Byte>> imageList,int playerCount,int cardPerPlayer,int frameCount,int[] indexArray)
            : base(playerCount, cardPerPlayer, indexArray)
        {
            this.imageList = imageList;
            this.frameCount = frameCount;
        }
        public override Image<Bgr, Byte> getImage(int i, int j)
        {
            if (indexArray[i * playerCount + j] >= imageList.Count)
                return imageList[imageList.Count - 1];
            else if (indexArray[i * playerCount + j] < 0)
                return imageList[0];
            else
                return imageList[indexArray[i * playerCount + j]];
        }
    }

    class SingleFileManager : AbstractSingleManager
    {
        private Capture capture;
        
        public SingleFileManager(string fileName, int playerCount, int cardPerPlayer, int[] indexArray)
            : base(playerCount, cardPerPlayer, indexArray)
        {
            this.capture = new Capture(fileName);
            this.frameCount = (int)capture.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_COUNT);
        }
        public override Image<Bgr, Byte> getImage(int i, int j)
        {
            int index = indexArray[i * playerCount + j];
            capture.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_POS_FRAMES, index);

            //bool grab = capture.Grab();
            //return capture.RetrieveBgrFrame(indexArray[i * playerCount + j]);
            return capture.QueryFrame().Clone();
        }
    }

    class DualFileManager : ImageManager
    {
        private Capture capture1;
        private Capture capture2;
        protected int playerCount;
        protected int cardPerPlayer;
        protected int[] indexArray;
        protected bool[] inCap2;
        protected int[] sourceArray;
        protected int frameCount1;
        protected int frameCount2;
        public DualFileManager(string file1,string file2,int playerCount, int cardPerPlayer, int[] indexArray,bool[] inCap2)
        {
            this.capture1 = new Capture(file1);
            this.frameCount1 = (int)capture1.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_COUNT);
            this.capture2 = new Capture(file2);
            this.frameCount2 = (int)capture2.GetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_COUNT);
            this.inCap2 = inCap2;
            this.playerCount = playerCount;
            this.cardPerPlayer = cardPerPlayer;
            this.indexArray = indexArray;
            this.sourceArray = (int[])indexArray.Clone();
        }
        public int PlayerCount
        {
            get { return playerCount; }
        }
        public int CardPerPlayer
        {
            get { return cardPerPlayer; }
        }
        public void moveFore(int i, int j)
        {
            if (indexArray[i * playerCount + j] > 0)
                indexArray[i * playerCount + j]--;
        }
        public void moveBack(int i, int j)
        {
            int count = 0;
            if (inCap2[i * playerCount + j])
                count = frameCount2;
            else
                count = frameCount1;
            if (indexArray[i * playerCount + j] < count - 1)
                indexArray[i * playerCount + j]++;
        }
        public void reset(int i, int j)
        {
            indexArray[i * playerCount + j] = sourceArray[i * playerCount + j];
        }
        public Image<Bgr, Byte> getImage(int i, int j)
        {
            int index = indexArray[i * playerCount + j];
            if (inCap2[i * playerCount + j])
            {
                capture2.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_POS_FRAMES, index);
                return capture2.QueryFrame().Clone();
            }
            else
            {
                capture1.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_POS_FRAMES, index);
                return capture1.QueryFrame().Clone();
            }
        }
    }
}
